/**
 * SpelGUI
 * @author jeroen :-P wil de traditie natuurlijk niet breken
 */

import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class SpelController extends JFrame implements ActionListener{
	private Spelronde spelronde;
	private JButton hit,stand,split,doubledown,insurance;
	private JLabel playerLabel,playing;
	private JMenuBar menu = new JMenuBar();
	private JMenu file = new JMenu("File");
	private JMenu help = new JMenu("Help");
	private JMenuItem about = new JMenuItem("About");
	private JMenuItem score = new JMenuItem("Score");
	private JMenuItem exit = new JMenuItem("Exit");
	private CardPanel dealerPanel, playerPanel;
	private JPanel buttonPanel;
	private Spel spel;
	private int aanDeBeurt = 0;
	private Vector<Deelname> spelers;

	public SpelController(Spel s){
		spel = s;
		/** 
		 * Menu spul test
		 */
		menu.add(file);
		menu.add(help);
		help.add(about);
		file.add(score);
		file.add(exit);
		about.addActionListener(this);
		score.addActionListener(this);
		exit.addActionListener(this);
		
		setJMenuBar(menu);
		
		/**
		 * Frame inhoud
		 */
		Container c = getContentPane();
		// GridLayout met 1 kolom
		c.setLayout(null);
		c.setBackground(new Color(0,102,26));
		// Drie panels in de kolom
		dealerPanel = new CardPanel();
		playerPanel = new CardPanel();
		buttonPanel = new JPanel();
		
		// Alle panels hebben 1 rij met oneindig plaatsen
		buttonPanel.setLayout(new GridLayout(1,0));
		
		JLabel dealerLabel = new JLabel("Dealer cards");
		dealerLabel.setForeground(Color.WHITE);
		dealerLabel.setBounds(5, 0, 100, 21);
		c.add(dealerLabel);
		dealerPanel.setBounds(5, 25, 800, 100);
		c.add(dealerPanel);
		playing = new JLabel();
		playerLabel = new JLabel("Player cards");
		playerLabel.setForeground(Color.WHITE);
		playerLabel.setBounds(5, 130, 100, 21);
		c.add(playerLabel);
		playerPanel.setBounds(5, 160, 800, 100);
		c.add(playerPanel);
		buttonPanel.setBounds(5, 300, 800, 50);
		c.add(buttonPanel);
		playing = new JLabel("spelernaam");
		playing.setForeground(Color.WHITE);
		playing.setBounds(300, 130, 200, 25);
		c.add(playing);
		JButton b = new JButton();
		ImageIcon i = new ImageIcon("button.gif");
		b.setIcon(i);
		getContentPane().add(b);		
		
		//initializing icons & button
		ImageIcon normal_icon = new ImageIcon("buttons/button_hit.gif");
		ImageIcon pressed_icon = new ImageIcon("buttons/button_pressed_hit.gif");
		hit = new JButton();
		ImageIcon normal_icon2 = new ImageIcon("buttons/button_stand.gif");
		ImageIcon pressed_icon2 = new ImageIcon("buttons/button_pressed_stand.gif");
		stand = new JButton();
		ImageIcon normal_icon3 = new ImageIcon("buttons/button_split.gif");
		ImageIcon pressed_icon3 = new ImageIcon("buttons/button_pressed_split.gif");
		ImageIcon disabled_icon3 = new ImageIcon("buttons/button_disabled_split.gif");
		split = new JButton();
		ImageIcon normal_icon4 = new ImageIcon("buttons/button_doubledown.gif");
		ImageIcon pressed_icon4 = new ImageIcon("buttons/button_pressed_doubledown.gif");
		ImageIcon disabled_icon4 = new ImageIcon("buttons/button_disabled_doubledown.gif");
		doubledown = new JButton();
		ImageIcon normal_icon5 = new ImageIcon("buttons/button_insurance.gif");
		ImageIcon pressed_icon5 = new ImageIcon("buttons/button_pressed_insurance.gif");
		ImageIcon disabled_icon5 = new ImageIcon("buttons/button_disabled_insurance.gif");
		insurance = new JButton();

		//setting icons for different states
		hit.setIcon(normal_icon);
		hit.setPressedIcon(pressed_icon);		
		stand.setIcon(normal_icon2);
		stand.setPressedIcon(pressed_icon2);
		split.setIcon(normal_icon3);
		split.setPressedIcon(pressed_icon3);
		split.setDisabledIcon(disabled_icon3);
		doubledown.setIcon(normal_icon4);
		doubledown.setPressedIcon(pressed_icon4);
		doubledown.setDisabledIcon(disabled_icon4);
		insurance.setIcon(normal_icon5);
		insurance.setPressedIcon(pressed_icon5);
		insurance.setDisabledIcon(disabled_icon5);

		//adding button to the applet
		getContentPane().add(hit);
		getContentPane().add(stand);
		getContentPane().add(split);
		getContentPane().add(doubledown);
		getContentPane().add(insurance);
		
		hit.setFocusable(false);
		hit.setBorder(null);
		stand.setFocusable(false);
		stand.setBorder(null);
		split.setFocusable(false);
		split.setBorder(null);		
		doubledown.setFocusable(false);
		doubledown.setBorder(null);
		insurance.setFocusable(false);
		insurance.setBorder(null);
		
		buttonPanel.add(hit);
		buttonPanel.add(stand);
		buttonPanel.add(split);
		buttonPanel.add(doubledown);
		buttonPanel.add(insurance);
		hit.addActionListener(this);
		stand.addActionListener(this);
		split.addActionListener(this);
		doubledown.addActionListener(this);
		insurance.addActionListener(this);
		
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setTitle("BlackJack");
		setResizable(false);
		setSize(825, 560);
		setVisible(true);
		
		/**
		 * Start de Ronde
		 */
		initRonde();
	}

	public void actionPerformed(ActionEvent e)
	{	if(e.getSource() == about)
		{	
		new About();
		}
		else if(e.getSource() == score){
			String[] kolom = {"Ronde", "Naam", "Inzet", "Score"};
			int aantalRegels = spel.getSpelers().length * 3;
			for(int i = 0; i < spel.getRondes().size(); i++)
			{	aantalRegels += spel.getRondes().elementAt(i).getAantalDeelnames();
			}
			//int aantalRegels = spel.getSpelers().length*spel.getRondes().size()+spel.getSpelers().length*3;		
			String[][] data = new String[aantalRegels][4];
			int regel = 0;
			for (Speler speler : spel.getSpelers()){
				double totaalInzet = 0;
				int rondeNummer = 0;
				double gemiddeldeScore = 0;
				double nettoWinstVerlies = 0;
				for (Iterator<Spelronde> i = spel.getRondes().iterator(); i.hasNext();){
					Spelronde ronde = i.next();
					if (ronde != spelronde){
						rondeNummer++;
						Vector<SpelerDeelname> spelers = ronde.getDeelnamesBySpeler(speler);
						for(int j=0; j < spelers.size(); j++)
						{
							data[regel][0] = rondeNummer+"";
							data[regel][1] = spelers.elementAt(j).getNaam();
							data[regel][2] = spelers.elementAt(j).getInzet()+"";
							data[regel][3] = spelers.elementAt(j).getScore()+"";
							
							totaalInzet += spelers.elementAt(j).getInzet();
							nettoWinstVerlies += spelers.elementAt(j).getScore();
							gemiddeldeScore += spelers.elementAt(j).getScore();
							
							regel++;
						}
					}
				}
				regel++;
				data[regel][0] = "Totaal inzet:";
				data[regel][1] = totaalInzet+"";
				data[regel][2] = "Netto score:";
				data[regel][3] = nettoWinstVerlies+"";
				
				regel++;
				data[regel][0] = "Gemiddeld winst/verlies:";
				data[regel][1] = 1.0 * gemiddeldeScore / rondeNummer +"";
				
				regel += 2;
			}
			new ScoreController(data, kolom);
		}
		else if(e.getSource() == exit)
			dispose();
		else if(e.getSource() == hit){
			try {
				hit();
			}catch (BustedException be){
				JOptionPane.showMessageDialog(this, "Je bent busted");
				stand();
			}
		}
		else if(e.getSource() == stand)
			stand();
		else if(e.getSource() == split)
			split();
		else if(e.getSource() == doubledown)
			doubledown();
		else if(e.getSource() == insurance)
			insurance();
	}
	/**
	 * Trekt en tekent een kaart voor de speler
	 * @throws BustedException
	 */
	public void hit() throws BustedException{	
		Kaart k = spelronde.hit();
		spelers.get(aanDeBeurt).addKaart(k);
		playerPanel.addKaart(k);
		split.setEnabled(false);
		doubledown.setEnabled(false);
		if (spelers.get(aanDeBeurt).getPunten() > 21){
			throw new BustedException("Je bent busted");
		}
		
	}
	/**
	 * Trekt en tekent een kaart voor de dealer
	 * @throws BustedException
	 */
	public void dealerHit() throws BustedException{
		Kaart k = spelronde.hit();
		spelronde.getDealer().addKaart(k);
		dealerPanel.addKaart(k);
		if (spelronde.getDealer().getPunten() > 21){
			throw new BustedException("Dealer is busted");
		}
	}
	/**
	 * Beeindigt de ronde van de speler en gaat verder met de volgende speler.
	 */
	public void stand(){	
		int punten = spelers.get(aanDeBeurt).getPunten();
		if (punten < 22){
			System.out.println(spelers.get(aanDeBeurt).getNaam() + " heeft " + punten + " punten.");
		}else{
			System.out.println(spelers.get(aanDeBeurt).getNaam() + " is busted.");
		}
		try {
			volgendeSpeler();
		}catch (BustedException be){
			// Komt in de praktijk nooit voor
		}catch (EindeRondeException ee){
			eindeRonde();
		}catch (BlackJackException bje){
			System.out.println(bje.getMessage());
		}
	}
	/**
	 * Split 
	 */
	public void split()
	{	
		if(spelronde != null)
		try
		{	spelronde.split(spelers.get(aanDeBeurt));
			playerPanel.removeSplit();
			repaint();
			hit();
			spelers.get(aanDeBeurt).checkBlackJack();
			checkInsurance();
			checkDouble();
		}
		catch(GeenGeldException gge)
		{	JOptionPane.showMessageDialog(this, gge.getMessage(),
				"Split",JOptionPane.ERROR_MESSAGE);
			split.setEnabled(false);
			doubledown.setEnabled(false);
		}
		catch(BustedException be){}
		catch (BlackJackException bje)
		{	System.out.println(bje.getMessage());
		}
		split.setEnabled(false);
		doubledown.setEnabled(false);
	}
	/**
	 * Laat de inzet popup zien en zorgt dat er geldige bedragen worden ingevoerd.
	 */
	public void inzetten(){
		playing.setText(spelers.get(aanDeBeurt).getNaam() + " is aan de beurt.");
		double d = 0;
		String s = "";
		while(true)
			try{
				d = Double.parseDouble(JOptionPane.showInternalInputDialog(this.getContentPane(),"Inzetten " + s));
				spelronde.inzetten(spelers.get(aanDeBeurt), d);
				break;
			}
			catch(GeenGeldException ge){
				s ="\nError: " + ge.getMessage();
			}
			
			catch(IllegalArgumentException ie){
				s ="\nError: " + ie.getMessage();
			}
		
			catch(Exception e){
				s="\nError: Vul een geldige waarde in!";
			}
	}
	/**
	 * Double down implementatie
	 */
	public void doubledown()
	{	if(spelronde != null)
		{	try{
				spelronde.doubledown(spelers.get(aanDeBeurt));
				hit();
				try{Thread.sleep(1000);}catch(Exception e){}
				stand();
			}
			catch(GeenGeldException ge){
				JOptionPane.showMessageDialog(this, ge.getMessage(),
                        "Double down", JOptionPane.ERROR_MESSAGE);
				doubledown.setEnabled(false);
				split.setEnabled(false);
			}
			catch(BustedException be){
				System.out.println("Je bent busted");
			}
		}
	}
	/**
	 * Insurance implementatie
	 */
	public void insurance()
	{	if(spelronde != null)
		{	try
			{	spelronde.insurance(spelers.get(aanDeBeurt));
			}
			catch(GeenGeldException ge)
			{	JOptionPane.showMessageDialog( this, ge.getMessage(),
					"Insurance", JOptionPane.ERROR_MESSAGE);
			}
		insurance.setEnabled(false);
		}
	}
	/**
	 * Zorgt dat de volgende speler aan de beurt komt.
	 * Als er geen spelers meer zijn om aan de beurt te komen
	 * dan wordt de ronde afgesloten door een EindeRondeException
	 * te gooien.
	 * 
	 * @throws EindeRondeException
	 * @throws BustedException
	 * @throws BlackJackException
	 */
	public void volgendeSpeler() throws EindeRondeException, BustedException, BlackJackException{
		aanDeBeurt++;
		if (aanDeBeurt == spelronde.getAantalDeelnames()){
			throw new EindeRondeException("Laatste speler geweest");
		}
		System.out.println("= " + spelers.get(aanDeBeurt).getNaam() + " is aan de beurt. =");
		playerPanel = clearPanel(playerPanel, 160);
		if (spelers.get(aanDeBeurt).getHand() != 1){
			// het is dus een split
			playerPanel.addKaart(spelers.get(aanDeBeurt).kaarten.get(0));
			hit();
			spelers.get(aanDeBeurt).checkBlackJack();
			checkInsurance();
			checkDouble();
		}else{
			inzetten();
			hit();
			hit();
			spelers.get(aanDeBeurt).checkBlackJack();
			checkSplit();
			checkDouble();
			checkInsurance();
		}
	}
	/**
	 * Deze functie bekijkt wie er mee doet en haalt deelnames weg
	 * als mensen niet meer mee doen. Aan het einde van het spel
	 * gooit hij een exception dat het is afgelopen. 
	 * @throws EindeSpelException
	 */
	
	
	public void wieDoetErMee()throws EindeSpelException{
		for(int i = 0; i < spelers.size()-1; i++){
			SpelerDeelname sd = (SpelerDeelname) spelers.get(i);
			if(sd.getSaldo() < spel.getMinInzet()){
					spelers.remove(i);
					i = i - 1;
			}

			if(spelers.size() == 1){
				throw new EindeSpelException("Het Spel is afgelopen");
			}
			
		}
		
		spelronde.setAantalDeelnames((spelers.size()-1));
	}
	
	/**
	 * Verwijderd alle kaarten van het het meegegeven panel.
	 * 
	 * @param p Cardpanel
	 * @param y int
	 * @return Cardpanel
	 */
	public CardPanel clearPanel(CardPanel p, int y){
		getContentPane().remove(p);
		p = new CardPanel();
		p.setBounds(5, y, 800, 100);
		getContentPane().add(p);
		repaint();
		return p;
	}
	/**
	 * Beeindigd de ronde en voert de dealer ronde uit.
	 * Roept ook het einde ronde score scherm op.
	 */
	public void eindeRonde(){
		while (spelronde.getDealer().getPunten() < 17){
			try {
				dealerHit();
				spelronde.getDealer().checkBlackJack();
			}catch (BustedException be){
				System.out.println(be.getMessage());
			}catch (BlackJackException bje){
				System.out.println(bje.getMessage());
			}
		}
		System.out.println("Dealer heeft " + spelronde.getDealer().getPunten() + " punten.");
		String[][] data = spelronde.berekenRonde();
		JOptionPane.showMessageDialog(this, "Einde van de Ronde");
		playerPanel = clearPanel(playerPanel, 160);
		dealerPanel = clearPanel(dealerPanel, 25);
		String[] kolom = {"Naam", "Score", "Saldo"};
		new ScoreController(data, kolom);
		initRonde();
	}
	/**
	 * Start een nieuwe ronde. Hij disabelt hier buttons die nog niet van toepassing zijn.
	 * start de nieuwe ronde, doet eerst een dealerhit en hit daarna voor de speler, kijkt of
	 * insurance van toepassing is en vangt wat Exceptions op.
	 */
	public void initRonde(){
		System.out.println("== Nieuwe ronde ==");
		spelronde = spel.nieuweRonde();	
		spelers = spelronde.getDeelnames();
		try{
			wieDoetErMee();
			aanDeBeurt = 0;
			dealerHit();
			inzetten();
			hit();
			hit();
			checkSplit();
			checkDouble();
			checkInsurance();
			spelers.get(aanDeBeurt).checkBlackJack();
		}catch (BustedException be){
			System.out.println(be.getMessage());
		}catch (BlackJackException bje){
			System.out.println(bje.getMessage());
		}
		catch (EindeSpelException es){
			System.out.println(es.getMessage());
			System.exit(0);
		}
	}
	/**
	 * Zet de split button aan als dat gepast is.
	 */
	public void checkSplit(){
		if (spelers.get(aanDeBeurt).checkSplit())
			split.setEnabled(true);
		else
			split.setEnabled(false);
	}
	/**
	 * Zet de double button aan als dat gepast is.
	 */
	public void checkDouble(){
		if(spelers.get(aanDeBeurt).getPunten() > 8 && spelers.get(aanDeBeurt).getPunten() < 12)
			doubledown.setEnabled(true);
		else
			doubledown.setEnabled(false);
	}
	/**
	 * Zet de insurance button aan als dat gepast is.
	 */
	public void checkInsurance()
	{	if(spelronde.getDealer().getPunten() == 11)
			insurance.setEnabled(true);
		else
			insurance.setEnabled(false);
	}
}